`include "s:/define.v"
`include "s:/ppdefine.v"
module ppunit
#(
	parameter PPID = 32'h0
)
(
input clk,
input rst_n,
//instr bus
input [31:0] instr,
input [31:2] instr_addr,
//to instr_addr manager
output  [31:2] instr_req_addr,
output  instr_req,
//data bus
input [127:0] data,
input [31:4] data_addr,
//to data_addr manager
output [31:2] data_req_addr,
output reg data_req,
output [31:0] wr_data,
output [31:2]wr_data_addr,
output reg wr_data_en,
input wr_data_consumed,
//status
output reg busy
);
reg  branch_taken;
wire [31:0] resp_instr;
wire resp_instr_v;
wire cnd_v;//condition established
wire [7:0] opcode=resp_instr[31:24];
wire [1:0]opcode_supp=resp_instr[11:10];
wire [31:0] Imm={{16{resp_instr[15]}},resp_instr[15:0]};
wire [17:2] jmp_to_iaddr=resp_instr[15:0];
wire [3:0] d_rA=resp_instr[23:20];
wire [3:0] d_rB=resp_instr[19:16];
wire [3:0] d_rC=resp_instr[15:12];

wire [31:0] d_rvalA,d_rvalB;
reg [3:0] w_dst;
wire [31:0] e_valE;
reg alu_en;
wire e_valE_valid;
reg [1:0] w_wordsel;
reg[2:0] pp_state;
reg [31:2] mem_addr;
wire resp_v;
wire start_pp;
wire [31:0] resp_data;
reg [31:0] w_val;
assign data_req_addr=mem_addr[31:2];
assign wr_data=d_rvalA;
assign wr_data_addr=mem_addr;

reg [7:0] opcode_r;
reg [1:0] opcode_supp_r;
reg [31:0] d_rvalA_r,d_rvalB_r;
reg [3:0] d_rB_r,d_rC_r;
always @ (posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            pp_state<=`PP_IDLE;
            w_dst<=4'hF;
				d_rB_r<=4'hF;d_rC_r<=4'hF;
				w_val<=32'h0;
            branch_taken<=0;
            alu_en<=0;
            w_wordsel<=2'b00;
				busy<=1'b0;
				mem_addr<=30'h0;
				wr_data_en<=1'b0;
				data_req<=0;
				
				opcode_r<=8'h0;opcode_supp_r<=2'b0;
				d_rvalA_r<=32'h0;d_rvalB_r<=32'h0;
        end
    else
        begin
            case(pp_state)
            `PP_IDLE:
                begin
                    branch_taken<=0;
                    w_dst<=4'hF;
						  busy<=1'b0;
						  if(start_pp)
							  begin
							  pp_state<=  `PP_DEC;
							  busy<=1'b1;
							  end
						  else
							  busy<=1'b0;
                end
            `PP_DEC:
                begin
                    if(resp_instr_v && opcode[7]==`PP_INS)
                    begin
                        if(opcode[6:0]==`HALT)
                            begin
                                pp_state<=`PP_IDLE;
										  busy<=1'b0;
                                branch_taken<=0;
                            end
                        else if(cnd_v && opcode[6:4]==`GROUP_JMP)
                            begin
                                branch_taken<=1;
                            end
                        else if(opcode[6:4]==`GROUP_OP)
                            begin
                                pp_state<=`PP_EXEC;
										  opcode_r<=opcode;opcode_supp_r<=opcode_supp;
										  d_rvalA_r<=d_rvalA;d_rvalB_r<=d_rvalB;d_rC_r<=d_rC;
                                w_wordsel<=opcode_supp;
                                alu_en<=1;
                                branch_taken<=0;
                            end
                        else if(opcode[6:0]==`RMMOV16 || opcode[6:0]==`RMMOV32) 
                            begin
                                pp_state<=`PP_STORE;
                                mem_addr<=d_rvalB+Imm;
                                wr_data_en<=1;
                                branch_taken<=0;
                            end
                        else if(opcode[6:0]==`MRMOV16 || opcode[6:0]==`MRMOV32) 
                            begin
                                pp_state<=`PP_LOAD;
                                mem_addr<=d_rvalA+Imm;
										  d_rB_r<=d_rB;
                                data_req<=1;
                                w_wordsel<=opcode[6:0]==`MRMOV16?2'b01:2'b00;
                                branch_taken<=0;
                            end
                        else if(opcode[6:0]==`IRMOV16)
                            begin
                                w_dst<=d_rB;
                                w_val<=Imm;
                                w_wordsel<=resp_instr[23:20];
                            end
                    end
                end
            `PP_EXEC:
                begin
                    if(e_valE_valid)
                        begin
                            w_dst<=d_rC_r;
                            w_val<=e_valE;
									 alu_en<=0;
                            pp_state<=`PP_DEC;
                        end
                end
            `PP_LOAD:
                begin
                    if(resp_v)
                    begin
                        data_req<=0;
                        w_dst<=d_rB_r;
                        w_val<=resp_data;
                        pp_state<=`PP_DEC;
                    end
                end
            `PP_STORE:
                begin
                    if(wr_data_consumed)
                        begin
                            wr_data_en<=0;
                            pp_state<=`PP_DEC;
                        end
                end
            default:
                begin
						pp_state<=`PP_IDLE;
						w_dst<=4'hF;
						branch_taken<=0;
						alu_en<=0;
						w_wordsel<=2'b00;
						busy<=1'b0;
                end
				endcase
        end
end

ppiaddrreq 
#(.PPID(PPID))
u_ppiaddrreq(
.clk(clk),
.rst_n(rst_n),
.instr(instr),
.instr_addr(instr_addr),
.resp_instr_v(resp_instr_v),
.resp_instr(resp_instr),
.start_pp(start_pp),

.jmp_to_iaddr(jmp_to_iaddr),
.branch_taken(branch_taken),
.pp_state(pp_state),

.instr_req_addr(instr_req_addr),
.instr_req(instr_req)
);
wire [2:0] cc,alucc;
 ppregfile
#(.PPID(PPID))
 u_ppregfile(
.clk(clk),
.rst_n(rst_n),
.d_srcA(d_rA),
.d_srcB(d_rB),
.d_rvalA(d_rvalA),
.d_rvalB(d_rvalB),
.w_dst(w_dst), 
.w_wordsel(w_wordsel),//00-rx,01-rxL,1x-rxH
.w_val(w_val)
   );



 ppalu u_ppalu(
.clk(clk),
.rst_n(rst_n),
.alu_en(alu_en),
.E_opcode(opcode_r),
.E_opcode_supp(opcode_supp_r),
.E_valA(d_rvalA_r),
.E_valB(d_rvalB_r),
.e_valE(e_valE),
.e_valE_valid(e_valE_valid),
.e_setcc(setcc),
.e_alucc(alucc)
   );

cond U_cond(
	//output
	.e_cnd(cnd_v),
	//input
	.E_op_cnd(opcode_r[3:0]),
	.e_cc(cc));
	
regCC U_regCC
	(//output
	.e_cc(cc),
	//input
	.clk(clk),
	.rst_n(rst_n),
	.e_alucc(alucc),
	.e_setcc(setcc));
    
pploadchk u_pploadchk
(
.clk(clk),
.rst_n(rst_n),
.data(data),
.data_addr(data_addr),
.data_req_addr(data_req_addr),
.data_req(data_req),
.resp_data(resp_data),
.resp_v(resp_v)
);
endmodule
